package com.xunwulian.base.util;

import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.UUID;

/**
 * Created by Administrator on 2016/12/21.
 * <p>
 * 文件工具类
 * 读、写、拷贝文件
 */
public class FileUtil {

    // 日志工具
    private MyLogUtil myLogUtil = new MyLogUtil(FileUtil.class);

    /**
     * 读取文件的内容
     *
     * @param path 文件的路径
     * @return 文件的内容
     */
    public String readFile(String path) {
        File file = new File(path);
        return readFile(file);
    }

    /**
     * 读取文件的内容
     *
     * @param root 文件的根路径
     * @param path 文件的子路径
     * @return 文件的内容
     */
    public String readFile(String root, String path) {
        File file = new File(root, path);
        return readFile(file);
    }

    /**
     * 读取文件的内容
     *
     * @param file 要读取的文件
     * @return 文件的内容
     */
    public String readFile(File file) {
        StringBuilder content = new StringBuilder();

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            int size = 1024;
            byte[] buff = new byte[size];
            while (fis.available() != 0) {
                int length = fis.read(buff, 0, size);
                content.append(new String(buff, 0, length));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeIO(fis);
        }

        return content.toString();
    }

    /**
     * 写入文件
     *
     * @param path    文件的路径
     * @param content 写入的内容
     */
    public String writeFile(String path, String content) {
        File file = new File(path);
        return writeFile(file, content);
    }

    /**
     * 写入文件
     *
     * @param root    文件的根路径
     * @param path    文件的子路径
     * @param content 写入的内容
     */
    public String writeFile(String root, String path, String content) {
        File file = new File(root, path);
        return writeFile(file, content);
    }

    /**
     * 写入文件，上传文件时可以用
     *
     * @param upload         上传的文件
     * @param root           写入的根路径
     * @param uploadFileName 文件名
     * @return 写入的文件名
     */
    public String writeFile(File upload, String root, String uploadFileName) {

        if (upload == null) {
            return null;
        }
        if (StringUtils.isBlank(root)) {
            root = "/";
        }

        uploadFileName = createFileName(uploadFileName);

        File uRoot = new File(root);
        if (!uRoot.exists()) {
            uRoot.mkdirs();
        }
        // 以root为根路径创建文件
        File uFile = new File(root, uploadFileName);

        writeFile(uFile, upload);

        // 返回创建的文件名
        return uploadFileName;
    }

    /**
     * 写入文件
     *
     * @param file    写入的文件
     * @param content 写入的内容
     */
    public String writeFile(File file, String content) {
        FileOutputStream fos = null;
        StringReader sr = null;
        try {
            fos = new FileOutputStream(file);
            sr = new StringReader(content);
            int size = 1024;
            char[] buff = new char[size];
            int length;
            while ((length = sr.read(buff, 0, size)) != -1) {
                String sub = new String(buff, 0, length);
                fos.write(sub.getBytes());
            }
            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            closeIO(sr);
            closeIO(fos);
        }

        try {
            return file.getCanonicalPath();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 写入文件，拷贝文件
     *
     * @param fileA 写入的文件
     * @param fileB 源文件
     * @return 写入的文件路径
     */
    public String writeFile(File fileA, File fileB) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(fileB);
            fos = new FileOutputStream(fileA);
            byte[] buffer = new byte[1024];
            int length;
            while (-1 != (length = fis.read(buffer, 0, buffer.length))) {
                fos.write(buffer, 0, length);
            }
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            closeIO(fos);
            closeIO(fis);
        }

        try {
            return fileA.getCanonicalPath();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 关闭可关闭的流
     *
     * @param closeable 可关闭的流
     */
    public void closeIO(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取文件的类型
     *
     * @param upload 文件
     * @return 文件类型
     */
    public String getFileContentType(File upload) {
        try {
            return getFileContentType(upload.getCanonicalPath());
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取文件的类型
     *
     * @param uploadFilePath 文件路径
     * @return 文件类型
     */
    public String getFileContentType(String uploadFilePath) {
        String contentType = null;

        try {
            URL url = new URL("file:" + uploadFilePath);
            URLConnection connection = url.openConnection();
            contentType = connection.getContentType();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return contentType;
    }

    /**
     * 创建文件名
     *
     * @param uploadFileName 原始文件名
     * @return 新的文件名
     */
    public String createFileName(String uploadFileName) {
        // 获取后缀先
        uploadFileName = uploadFileName.substring(uploadFileName
                .lastIndexOf("."));
        // 构建唯一路径
        uploadFileName = UUID.randomUUID().toString() + uploadFileName;

        return uploadFileName;
    }

    /**
     * 获取文件后缀
     *
     * @param path 文件路径
     * @return 文件后缀
     */
    public String getFileSuffix(String path) {
        return path.substring(path.lastIndexOf("."));
    }

    /**
     * 创建文件目录
     *
     * @param root 目录
     */
    public void createFileDirectory(String root) {
        File uRoot = new File(root);
        if (uRoot == null || !uRoot.exists() || !uRoot.isDirectory()) {
            uRoot.mkdirs();
        }
    }

    /**
     * 读取到字节数组1
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public byte[] toByteArray(String filePath) throws IOException {

        File f = new File(filePath);
        if (!f.exists()) {
            throw new FileNotFoundException(filePath);
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(f));
            int buf_size = 1024;
            byte[] buffer = new byte[buf_size];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            bos.close();
        }
    }

    /**
     * 读取到字节数组2
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public byte[] toByteArray2(String filePath) throws IOException {

        File f = new File(filePath);
        if (!f.exists()) {
            throw new FileNotFoundException(filePath);
        }

        FileChannel channel = null;
        FileInputStream fs = null;
        try {
            fs = new FileInputStream(f);
            channel = fs.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
            while ((channel.read(byteBuffer)) > 0) {
                // do nothing
                myLogUtil.log("reading");
            }
            return byteBuffer.array();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Mapped File way MappedByteBuffer 可以在处理大文件时，提升性能
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public byte[] toByteArray3(String filePath) throws IOException {

        FileChannel fc = null;
        RandomAccessFile rf = null;
        try {
            rf = new RandomAccessFile(filePath, "r");
            fc = rf.getChannel();
            MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0,
                    fc.size()).load();
            // System.out.println(byteBuffer.isLoaded());
            byte[] result = new byte[(int) fc.size()];
            if (byteBuffer.remaining() > 0) {
                // System.out.println("remain");
                byteBuffer.get(result, 0, byteBuffer.remaining());
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                rf.close();
                fc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
